#include "../server.h"

static OSSL_KEY user_passwd_key;

int user_init()
{/*{{{*/
    SVCNODE sn;
    char respond[100];
    char key[50];
    char *p;
    char *curr;
    char *rtn;
    int res;

    res=sn_create(cnfg_info._key_.sn_passwd_addr, SN_MODE_ONESHOT, &sn);
    if(res)
    {
        fprintf(stderr,
                "%s: svcnode init for sn_passwd fail, errcode:%d\n",
                __func__, res);
        return(-1);
    }
    res=sn_call(sn, "GETUSERPASSWDKEY", NULL, respond);
    if(res)
    {
        fprintf(stderr,
                "%s: call to sn_passwd fail, errcode:%d\n",
                __func__, res);
        return(-1);
    }
    curr=respond;
    rtn=para_get_item(respond, &curr);
    if(!rtn || strcmp(rtn, SOAR_ERR_OK))
    {
        fprintf(stderr, "%s: get user_passwd_key fail, errcode:%s\n",
                __func__, rtn?rtn:"null");
        return(-1);
    }
    p=para_get_item(respond, &curr);
    if(!p)
    {
        fprintf(stderr, "%s: user_passwd_key invalid\n", __func__);
        return(-1);
    }
    strcpy(key, p);
    //printf("key: %s\n", key);
    sn_free(sn);

    res=ossl_sym_load_key(OSSL_SYM_AES_128_CBC, OSSL_SYM_PASSWD, key,
            &user_passwd_key);
    if(res)
    {
        fprintf(stderr, "%s: load user_passwd_key fail, res:%d\n",
                __func__, res);
        return(-1);
    }

    return(0);
}/*}}}*/

#define USER_PASSWD_MIN_SIZE            6
#define USER_PASSWD_MAX_SIZE            15

SVC_FUNC(MAKEUSERPASSWD)
{/*{{{*/
    char para_desc[50];
    PARA para;
    char *rtn;
    char passwd[USER_PASSWD_MAX_SIZE+1];
    int plain_size;
    char enc[LONG_FILE_NM_SIZE+1];
    int enc_size;
    int res;

    sprintf(para_desc, "passwd(string:%d-%d)",
            USER_PASSWD_MIN_SIZE, USER_PASSWD_MAX_SIZE);
    res=para_load(request, para_desc, &para);
    if(res)
    {
        if(res > 0)
            errlog("%s: request(%s) no.%d para invalid",
                    __func__, request, res);
        else
            errlog("%s: para_load request(%s) fail, res:%d",
                    __func__, request, res);
        rtn=SOAR_ERR_PARA;
        goto GO_OUT;
    }
    para_copy_by_name(para, "passwd", passwd);
    para_free(para);

    plain_size=strlen(passwd);
    res=ossl_sym_encrypt(user_passwd_key,
            (unsigned char *)passwd, plain_size,
            (unsigned char *)enc, &enc_size);
    if(res)
    {
        errlog("%s: encrypt passwd fail, res:%d", __func__, res);
        rtn=SOAR_ERR_SECURE_ENCRYPT;
        goto GO_OUT;
    }
    expand_to_str((unsigned char *)enc, enc_size, enc);
    para_put_item(respond, enc);
    rtn=SOAR_ERR_OK;

GO_OUT:
    para_insert_item(respond, rtn);
    return(atoi(rtn));
}/*}}}*/

SVC_FUNC(VERIFYUSERPASSWD)
{/*{{{*/
    char para_desc[50];
    PARA para;
    char passwd[USER_PASSWD_MAX_SIZE+1];
    int plain_size;
    char enc[LONG_FILE_NM_SIZE+1];
    int enc_size;
    char passwd_enc[PASSWD_ENC_SIZE+1];
    int res;

    sprintf(para_desc, "passwd(string:%d-%d) passwd_enc(string:%d)",
            USER_PASSWD_MIN_SIZE, USER_PASSWD_MAX_SIZE,
            PASSWD_ENC_SIZE);
    res=para_load(request, para_desc, &para);
    if(res)
    {
        if(res > 0)
            errlog("%s: msg(%s) no.%d para invalid",
                    __func__, request, res);
        else
            errlog("%s: para_load msg(%s) fail, res:%d",
                    __func__, request, res);
        para_put_item(respond, SOAR_ERR_PARA);
        return(atoi(SOAR_ERR_PARA));
    }
    para_copy_by_name(para, "passwd", passwd);
    para_copy_by_name(para, "passwd_enc", passwd_enc);
    para_free(para);

    plain_size=strlen(passwd);
    res=ossl_sym_encrypt(user_passwd_key,
            (unsigned char *)passwd, plain_size,
            (unsigned char *)enc, &enc_size);
    if(res)
    {
        errlog("%s: encrypt passwd fail, res:%d", __func__, res);
        para_put_item(respond, SOAR_ERR_SECURE_ENCRYPT);
        return(atoi(SOAR_ERR_SECURE_ENCRYPT));
    }
    expand_to_str((unsigned char *)enc, enc_size, enc);
    if(strcmp(enc, passwd_enc) != 0)
    {
        para_put_item(respond, SOAR_ERR_SECURE_PASSWD_DISCORD);
        return(atoi(SOAR_ERR_SECURE_PASSWD_DISCORD));
    }
    para_put_item(respond, SOAR_ERR_OK);
    return(atoi(SOAR_ERR_OK));
}/*}}}*/

SVC_FUNC(ENCUSERMSG)
{/*{{{*/
    char *rtn;
    int res;

    char para_desc[50];
    PARA para;
    sprintf(para_desc, "msg(string:1-%d)", BUFFER_SIZE-1);
    res=para_load(request, para_desc, &para);
    if(res)
    {
        if(res > 0)
            errlog("%s: msg(%s) no.%d para invalid",
                    __func__, request, res);
        else
            errlog("%s: para_load msg(%s) fail, res:%d",
                    __func__, request, res);
        para_put_item(respond, SOAR_ERR_PARA);
        return(atoi(SOAR_ERR_PARA));
    }
    char *plain;
    para_ref_by_name(para, "msg", &plain);

    int plain_size=strlen(plain);
    //errlog("plain: %s", plain);
    char *enc=NULL;
    char *code=NULL;
    ALLOC_MULTI_DOERR(enc, char, plain_size*2,
            rtn=SOAR_ERR_RESOURCE;
            goto GO_OUT;
            );
    int enc_size;
    res=ossl_sym_encrypt(user_passwd_key,
            (unsigned char *)plain, plain_size,
            (unsigned char *)enc, &enc_size);
    if(res)
    {
        errlog("%s: encrypt user msg fail, res:%d", __func__, res);
        rtn=SOAR_ERR_SECURE_ENCRYPT;
        goto GO_OUT;
    }
    //errlog("encrypt: %d", enc_size);
    ALLOC_MULTI_DOERR(code, char, enc_size*2,
            rtn=SOAR_ERR_RESOURCE;
            goto GO_OUT;
            );
    int code_size; 
    res=ossl_encode(OSSL_ENCODE_BASE64,
            (unsigned char *)enc, enc_size,
            code, &code_size);
    if(res)
    {
        errlog("%s: ossl_encode fail, res:%d", __func__, res);
        rtn=SOAR_ERR_SECURE_ENCODE;
        goto GO_OUT;
    }
    //errlog("code: %s", code);
    base64_unwrap(code, code);
    para_put_item(respond, code);
    rtn=SOAR_ERR_OK;

GO_OUT:
    para_free(para);
    if(enc) free(enc);
    if(code) free(code);
    para_insert_item(respond, rtn);
    return(atoi(rtn));
}/*}}}*/

SVC_FUNC(DECUSERMSG)
{/*{{{*/
    char *rtn;
    int res;

    char para_desc[50];
    PARA para;
    sprintf(para_desc, "code(string:1-%d)", BUFFER_SIZE*2-1);
    res=para_load(request, para_desc, &para);
    if(res)
    {
        if(res > 0)
            errlog("%s: msg(%s) no.%d para invalid",
                    __func__, request, res);
        else
            errlog("%s: para_load request(%s) fail, res:%d",
                    __func__, request, res);
        para_put_item(respond, SOAR_ERR_PARA);
        return(atoi(SOAR_ERR_PARA));
    }
    char *code=NULL;
    ALLOC_MULTI_DOERR(code, char, BUFFER_SIZE*2,
            para_free(para);
            para_put_item(respond, SOAR_ERR_RESOURCE);
            return(atoi(SOAR_ERR_RESOURCE));
            );
    para_copy_by_name(para, "code", code);
    para_free(para);

    char *enc=NULL;
    char *plain=NULL;
    int enc_size;
    ALLOC_MULTI_DOERR(enc, char, BUFFER_SIZE*2,
            rtn=SOAR_ERR_RESOURCE;
            goto GO_OUT;
            );
    base64_wrap(code, code);
    res=ossl_decode(OSSL_ENCODE_BASE64,
            code, strlen(code),
            (unsigned char *)enc, &enc_size);
    if(res)
    {
        errlog("%s: ossl_decode fail, res:%d",
                __func__, res);
        rtn=SOAR_ERR_SECURE_DECODE;
        goto GO_OUT;
    }
    ALLOC_MULTI_DOERR(plain, char, BUFFER_SIZE*2,
            rtn=SOAR_ERR_RESOURCE;
            goto GO_OUT;
            );
    int plain_size;
    res=ossl_sym_decrypt(user_passwd_key,
            (unsigned char *)enc, enc_size,
            (unsigned char *)plain, &plain_size);
    if(res)
    {
        errlog("%s: encrypt user msg fail, res:%d", __func__, res);
        rtn=SOAR_ERR_SECURE_ENCRYPT;
        goto GO_OUT;
    }
    plain[plain_size]=ZERO;
    para_put_item(respond, plain);
    rtn=SOAR_ERR_OK;

GO_OUT:
    if(plain) free(plain);
    if(enc) free(enc);
    if(code) free(code);
    para_insert_item(respond, rtn);
    return(atoi(rtn));
}/*}}}*/
